﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using YKXiangQi.Adapters;
using YKXiangQi.Common;
using YKXiangQi.Controls;
using YKXiangQi.Enums;
using YKXiangQi.EventHandlers;
using YKXiangQi.Models;
using System.Linq;
using YKXiangQi.Utilities;

namespace YKXiangQi.ViewModels
{
    public class MainWindowViewModel : ViewModelBase
    {
        public IDialogService DialogService { get; set; }
        public BoardViewModel Board { get; set; }

        private PlayerViewModel _redPlayer;
        public PlayerViewModel RedPlayer
        {
            get { return _redPlayer; }
            set
            {
                _redPlayer = value;
                RaisePropertyChanged(() => this.RedPlayer);
            }
        }

        private PlayerViewModel _blackPlayer;
        public PlayerViewModel BlackPlayer
        {
            get { return _blackPlayer; }
            set
            {
                _blackPlayer = value;
                RaisePropertyChanged(() => this.BlackPlayer);
            }
        }

        public PlayerViewModel AnalyzeModeEngine { get;private set; }

        public StatusBarViewModel StatusBarContent { get; private set; }

        public TimerControlViewModel TimerControl { get; private set; }

        public ObservableCollection<PlayerViewModel> RedPlayerCollection { get; set; }
        public ObservableCollection<PlayerViewModel> BlackPlayerCollection { get; set; }
        public ObservableCollection<PlayerViewModel> Engines { get; set; }
        public ObservableCollection<EnumMapperViewModel<BoardSize>> BoardSizeOptions { get; set; }
        public ObservableCollection<LanguageViewModel> Languages { get; set; }
        public ObservableCollection<DockableViewModel> BottomPanelSource { get; set; }
        public ObservableCollection<DockableViewModel> RightPanelSource { get; set; }

        public RelayCommand RedPlayerChangedCommand { get; private set; }
        public RelayCommand BlackPlayerChangedCommand { get; private set; }
        public RelayCommand OpenSettingsCommand { get; private set; }
        public RelayCommand BoardSizeChangedCommand { get; private set; }
        public RelayCommand LanguageChangedCommand { get; private set; }
        public RelayCommand ViewBestMovesWindowCommand { get; private set; }
        public RelayCommand ViewCommandWindowCommand { get; private set; }
        public RelayCommand BottomPanelChildClosedCommand { get; private set; }
        public RelayCommand ViewHistoryWindowCommand { get; private set; }
        public RelayCommand ViewBookMovesWindowCommand { get; private set; }
        public RelayCommand ViewEngineInfoWindowCommand { get; private set; }
        public RelayCommand RightPanelChildClosedCommand { get; private set; }
        public RelayCommand FlipBoardCommand { get; private set; }
        public RelayCommand ViewBackgroundCommand { get; private set; }
        public RelayCommand ViewStatusBarCommand { get; private set; }
        public RelayCommand ChangeViewModeCommand { get; private set; }
        public RelayCommand InputCommand { get; private set; }
        public RelayCommand GoNowCommand { get; private set; }
        public RelayCommand OpenMoveDetailsCommand { get; private set; }
        public RelayCommand EditBoardCommand { get; private set; }
        public RelayCommand NewGameCommand { get; private set; }
        public RelayCommand AnalyzeModeEngineChangedCommand { get; private set; }
        public RelayCommand ViewTimerCommand { get; private set; } 

        private BestMovesViewModel BestMovesWindow { get; set; }
        private CommandViewModel CommandWindow { get; set; }
        private HistoryViewModel HistoryWindow { get; set; }
        private BookMovesViewModel BookMovesWindow { get; set; }
        private EngineInfoViewModel EngineInfoWindow { get; set; }
        private DebugViewModel DebugWindow { get; set; }

        private DockableViewModel _bottomPanelSelectedItem;
        public DockableViewModel BottomPanelSelectedItem
        {
            get { return _bottomPanelSelectedItem; }
            set
            {
                _bottomPanelSelectedItem = value;
                RaisePropertyChanged(() => this.BottomPanelSelectedItem);
            }
        }

        private bool _isBestMovesWindowVisible;
        public bool IsBestMovesWindowVisible
        {
            get { return _isBestMovesWindowVisible; }
            set
            {
                _isBestMovesWindowVisible = value;
                RaisePropertyChanged(() => IsBestMovesWindowVisible);
            }
        }

        private bool _isCommandWindowVisible;
        public bool IsCommandWindowVisible
        {
            get { return _isCommandWindowVisible; }
            set
            {
                _isCommandWindowVisible = value;
                RaisePropertyChanged(() => IsCommandWindowVisible);
            }
        }

        private bool _isTimerVisible = true;
        public bool IsTimerVisible
        {
            get { return _isTimerVisible; }
            set
            {
                _isTimerVisible = value;
                RaisePropertyChanged(() => IsTimerVisible);
            }
        }

        private ImageSource _background;
        public ImageSource Background
        {
            get { return _background; }
            set
            {
                _background = value;
                RaisePropertyChanged(() => Background);
            }
        }

        private bool _isStatusBarVisible = true;
        public bool IsStatusBarVisible
        {
            get { return _isStatusBarVisible; }
            set
            {
                _isStatusBarVisible = value;
                RaisePropertyChanged(() => IsStatusBarVisible);
            }
        }

        private bool _isAnalyzeMode;
        public bool IsAnalyzeMode
        {
            get { return _isAnalyzeMode; }
            set
            {
                _isAnalyzeMode = value;
                RaisePropertyChanged(() => IsAnalyzeMode);
                
                if(_isAnalyzeMode)
                {
                    Reset();
                    Analyze();
                }
                else
                {
                    StopAnalyze();
                }
            }
        }

        public MoveList MoveList { get; set; }

        public MainWindowViewModel()
        {
            DialogService = new DialogService();
            MoveList = new MoveList() {StartFen = Constant.DefaultFen};
            StatusBarContent = new StatusBarViewModel();
            TimerControl = new TimerControlViewModel();
            TimerControl.TimeOut += OnTimerTimeOut;
            
            Board = new BoardViewModel(BoardSize.Medium);
            Board.PieceMoved += OnPieceMoved;
            InitCommands();
            InitPlayes();
            InitViews();
            GetAllBoardSizes(BoardSize.Medium);
            GetAllLanguages();
        }

        private void InitCommands()
        {
            RedPlayerChangedCommand = new RelayCommand(RedPlayerChanged);
            BlackPlayerChangedCommand = new RelayCommand(BlackPlayerChanged);
            OpenSettingsCommand = new RelayCommand(OpenSettings);
            BoardSizeChangedCommand = new RelayCommand(BoardSizeChanged);
            LanguageChangedCommand = new RelayCommand(LanguageChanged);
            ViewBestMovesWindowCommand = new RelayCommand(ViewBestMovesWindow);
            ViewCommandWindowCommand = new RelayCommand(ViewCommandWindow);
            BottomPanelChildClosedCommand = new RelayCommand(BottomPanelChildClosed);
            ViewHistoryWindowCommand = new RelayCommand(ViewHistoryWindow);
            ViewBookMovesWindowCommand = new RelayCommand(ViewBookMovesWindow);
            ViewEngineInfoWindowCommand = new RelayCommand(ViewEngineInfoWindow);
            RightPanelChildClosedCommand = new RelayCommand(RightPanelChildClosed);
            FlipBoardCommand = new RelayCommand(FlipBoard);
            ViewBackgroundCommand = new RelayCommand(ViewBackground);
            ViewStatusBarCommand = new RelayCommand(ViewStatusBar);
            ChangeViewModeCommand = new RelayCommand(ChangeViewMode);
            InputCommand = new RelayCommand(OnInput);
            GoNowCommand = new RelayCommand(GoNow);
            OpenMoveDetailsCommand = new RelayCommand(OpenMoveDetails);
            EditBoardCommand = new RelayCommand(EditBoard);
            NewGameCommand = new RelayCommand(NewGame);
            AnalyzeModeEngineChangedCommand = new RelayCommand(AnalyzeModeEngineChanged);
            ViewTimerCommand = new RelayCommand(OnViewTimer);
        }

        private void InitPlayes()
        {
            var engines = new ObservableCollection<Engine>(Engine.LoadEnginesFromSettings());
            var players = engines.Select(engine => new PlayerViewModel(engine)).ToList();

            var human = (new Human());
            players.Insert(0, new PlayerViewModel(human) { IsChecked = true });

            Engines = new ObservableCollection<PlayerViewModel>(engines.Select(engine => new PlayerViewModel(engine)));
            RedPlayerCollection = new ObservableCollection<PlayerViewModel>(players);
            BlackPlayerCollection = new ObservableCollection<PlayerViewModel>(players.DeepClone());

            RedPlayer = RedPlayerCollection.FirstOrDefault(item => item.Player.Type == PlayerType.Human);
            BlackPlayer = BlackPlayerCollection.FirstOrDefault(item => item.Player.Type == PlayerType.Human);
        }

        private void InitViews()
        {
            IsBottomPanelVisible = true;
            IsRightPanelVisible = true;

            var bottomPanelSource = new ObservableCollection<DockableViewModel>();
            BestMovesWindow = new BestMovesViewModel();
            CommandWindow = new CommandViewModel();
            DebugWindow = new DebugViewModel();

            bottomPanelSource.Add(BestMovesWindow);
            bottomPanelSource.Add(CommandWindow);
            bottomPanelSource.Add(DebugWindow);

            BottomPanelSource = bottomPanelSource;
            BottomPanelSelectedItem = BestMovesWindow;
            IsBestMovesWindowVisible = true;
            IsCommandWindowVisible = true;

            var rightPanelSource = new ObservableCollection<DockableViewModel>();
            HistoryWindow = new HistoryViewModel();
            BookMovesWindow = new BookMovesViewModel();
            EngineInfoWindow = new EngineInfoViewModel();

            rightPanelSource.Add(HistoryWindow);
            rightPanelSource.Add(BookMovesWindow);
            rightPanelSource.Add(EngineInfoWindow);

            RightPanelSource = rightPanelSource;
            RightPanelSelectedItem = HistoryWindow;

            IsHistoryWindowVisible = true;
            IsBookMovesWindowVisible = true;
            IsEngineInfoVisible = true;
        }

        private void RedPlayerChanged(object param)
        {
            var playerViewModel = param as PlayerViewModel;
            if (playerViewModel == null) return;

            if (playerViewModel == RedPlayer)
            {
                playerViewModel.IsChecked = true;
                return;
            }

            var selectedItem = RedPlayerCollection.FirstOrDefault(item => item.IsChecked && item != playerViewModel);
            if (selectedItem != null)
            {
                selectedItem.IsChecked = false;
                if (selectedItem.Player is Engine)
                {
                    var selectedEngigne = selectedItem.Player as Engine;
                    selectedEngigne.Adapter.EngineOuputReceived -= OnEngineOutputReceived;
                    selectedEngigne.Adapter.Exit();
                }
            }

            if (IsAnalyzeMode)
                IsAnalyzeMode = false;

            RedPlayer = playerViewModel;

            var engine = playerViewModel.Player as Engine;
            if (engine != null && !engine.IsStarted)
            {
                engine.Adapter.EngineOuputReceived += OnEngineOutputReceived;
                if (engine.Adapter.Start() && Board.Turn == Sides.Red)
                    Go();
            }
        }

        private void BlackPlayerChanged(object param)
        {
            var playerViewModel = param as PlayerViewModel;
            if (playerViewModel == null) return;

            if (playerViewModel == BlackPlayer)
            {
                playerViewModel.IsChecked = true;
                return;
            }

            var selectedItem = BlackPlayerCollection.FirstOrDefault(item => item.IsChecked && item != playerViewModel);
            if (selectedItem != null)
            {
                selectedItem.IsChecked = false;
                if (selectedItem.Player is Engine)
                {
                    var selectedEngigne = selectedItem.Player as Engine;
                    selectedEngigne.Adapter.EngineOuputReceived -= OnEngineOutputReceived;
                    selectedEngigne.Adapter.Exit();
                }
            }

            if (IsAnalyzeMode)
                IsAnalyzeMode = false;

            BlackPlayer = playerViewModel;

            var engine = playerViewModel.Player as Engine;
            if (engine != null && !engine.IsStarted)
            {
                engine.Adapter.EngineOuputReceived += OnEngineOutputReceived;
                if (engine.Adapter.Start() && Board.Turn == Sides.Black)
                    Go();
            }
        }

        private void AnalyzeModeEngineChanged(object param)
        {
            var engineViewModel = param as PlayerViewModel;
            if (engineViewModel == null) return;

            var selectedEngine = Engines.FirstOrDefault(item => item.IsChecked && item != engineViewModel);
            if (selectedEngine != null)
            {
                selectedEngine.IsChecked = false;
                var engine = selectedEngine.Player as Engine;
                if (engine != null)
                {
                    engine.Adapter.EngineOuputReceived -= OnEngineOutputReceived;
                    engine.Adapter.Exit();
                }
            }

            engineViewModel.IsChecked = true;
            AnalyzeModeEngine = engineViewModel;
            IsAnalyzeMode = true;
        }

        private void OpenSettings(object param)
        {
            DialogService.ShowDialog("Settings", new SettingsViewModel(), "options.png");
        }

        private void BoardSizeChanged(object param)
        {
            var enumMapper = param as EnumMapperViewModel<BoardSize>;
            if (enumMapper == null) return;

            var selectedItem = BoardSizeOptions.FirstOrDefault(item => item.IsChecked && item != enumMapper);
            if (selectedItem != null)
            {
                selectedItem.IsChecked = false;

                Board.Size = enumMapper.Value;
                Board.Refresh();
            }
            else
                enumMapper.IsChecked = true;
        }

        private void LanguageChanged(object param)
        {
            var language = param as LanguageViewModel;
            if (language == null) return;

            var selectedItem = Languages.FirstOrDefault(item => item.IsChecked && item != language);
            if (selectedItem != null)
            {
                selectedItem.IsChecked = false;
            }
            else
            {
                language.IsChecked = true;
            }

        }

        private void FlipBoard(object param)
        {
            var flag = (bool)param;
            Board.IsFlipped = flag;
            Board.Refresh();
        }

        private void ViewBackground(object param)
        {
            var flag = (bool)param;
            Background = flag ? new BitmapImage(new Uri(@"pack://application:,,,/YKXiangQi;component/Background/bg2.jpg")) : null;
        }

        private void ViewStatusBar(object param)
        {
            var flag = (bool)param;
            IsStatusBarVisible = flag;
        }

        private void ChangeViewMode(object param)
        {
            var viewMode = (ViewMode)param;
            Board.ViewMode = viewMode;
        }

        private void OpenMoveDetails(object param)
        {
            var bestMove = param as BestMove;
            if (bestMove == null) return;

            DialogService.ShowDialog("Move Details", new MoveDetailsViewModel(bestMove.MoveList));
        }

        private void OnInput(object param)
        {
            var bestMovesViewModel = BottomPanelSource.FirstOrDefault(item => item is BestMovesViewModel);
            if (bestMovesViewModel != null)
                (bestMovesViewModel as BestMovesViewModel).AddMove(new BestMove() { Depth = 10 });
            var e = (InputCommandEventArgs)param;
            e.Output = "Invalid Command";
            e.Handled = true;
        }

        private void EditBoard(object param)
        {
            var editBoardViewModel = new EditBoardViewModel(Board.GetCurrentFen());
            var result = DialogService.ShowDialog("Edit Board", editBoardViewModel, "edit.png");
            if (result.HasValue && result.Value)
            {
                if (IsAnalyzeMode)
                    IsAnalyzeMode = false;
                else
                    Reset();
                Board.SetBoardPosition(editBoardViewModel.GetCurrentFen(),
                                        editBoardViewModel.IsRedFirst ? Sides.Red : Sides.Black);
            }
        }

        private void NewGame(object param)
        {
            Reset();
            Board.NewGame();
        }

        private void OnViewTimer(object param)
        {
            IsTimerVisible = (bool) param;
        }

        private void GetAllBoardSizes(BoardSize defaultSize)
        {
            var result = new ObservableCollection<EnumMapperViewModel<BoardSize>>();
            var enumMappers = EnumHelper.LoadEnums<BoardSize>();
            foreach (var enumMapper in enumMappers)
            {
                result.Add(new EnumMapperViewModel<BoardSize>(enumMapper));
            }

            var defaultItem = result.FirstOrDefault(item => item.Value == defaultSize);
            if (defaultItem != null)
                defaultItem.IsChecked = true;

            BoardSizeOptions = result;
        }

        private void GetAllLanguages()
        {
            var languages = new List<LanguageViewModel>();
            languages.Add(new LanguageViewModel(new Language()
            {
                Name = "English",
                CultureCode = "en-US",
            }) { IsChecked = true });
            languages.Add(new LanguageViewModel(new Language()
            {
                Name = "Vietnam",
                CultureCode = "vi-VN"
            }));

            Languages = new ObservableCollection<LanguageViewModel>(languages);
        }

        protected void OnPieceMoved(object sender, PieceMovedEventArgs e)
        {
            Board.ClearThinkingMoves();
            TimerControl.Tick();

            if (IsAnalyzeMode)
            {
                StopAnalyze();
                Analyze();
            }
            else
            {
                if (e.Type == PieceMovedType.Manual)
                {
                    var engine = Board.Turn == Sides.Red
                                     ? BlackPlayer.Player as Engine
                                     : RedPlayer.Player as Engine;

                    if (engine != null)
                        engine.Adapter.StopThinking();
                }

                Go();
            }
        }

        protected void Go()
        {
            var engine = GetCurrentPlayerEngine();
            if (engine == null) return;

            if (BestMovesWindow != null)
                BestMovesWindow.Clear();

            engine.Adapter.SetPosition(Board.GetCurrentFen());
            
            if (TimerControl.IsRunning)
                engine.Adapter.Go(TimerControl.Settings);
            else
                engine.Adapter.Go();
            
        }

        protected void GoNow(object param)
        {
            var engine = GetCurrentPlayerEngine();
            if (engine == null) return;
            engine.Adapter.Stop();
        }

        protected void StopThinking()
        {
            var engine = GetCurrentPlayerEngine();
            if (engine == null) return;
            engine.Adapter.StopThinking();
        }

        protected Engine GetCurrentPlayerEngine()
        {
            var engine = Board.Turn == Sides.Red
                             ? RedPlayer.Player as Engine
                             : BlackPlayer.Player as Engine;
            return engine;
        }

        protected void Reset()
        {
            StopThinking();
            
            var redPlayer = RedPlayerCollection.FirstOrDefault(x => x.Player is Human);
            if (redPlayer != null) redPlayer.IsChecked = true;
            RedPlayerChanged(redPlayer);

            var blackPlayer = BlackPlayerCollection.FirstOrDefault(x => x.Player is Human);
            if (blackPlayer != null) blackPlayer.IsChecked = true;
            BlackPlayerChanged(blackPlayer);

            if (BestMovesWindow != null)
                BestMovesWindow.Clear();
            if (StatusBarContent != null)
                StatusBarContent.Clear();
        }

        protected void Analyze()
        {
            if (AnalyzeModeEngine == null) return;
            var engine = AnalyzeModeEngine.Player as Engine;
            if(engine== null) return;

            if (!engine.IsStarted)
            {
                engine.Adapter.EngineOuputReceived += OnEngineOutputReceived;
                engine.Adapter.Start();
            }

            engine.Adapter.SetPosition(Board.GetCurrentFen());
            engine.Adapter.Analyze();
        }

        protected void StopAnalyze()
        {
            if (AnalyzeModeEngine == null) return;

            var engine = AnalyzeModeEngine.Player as Engine;
            if (engine != null)
            {
                engine.Adapter.StopThinking();
            }
        }

        protected void OnEngineOutputReceived(object sender, EngineOutputReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data))
                return;
            
            var info = e.Data.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).ToList();
            switch (info[0])
            {
                case Constant.FeedBacks.Id:
                    {
                        var data = string.Empty;
                        var index = 0;

                        if (info[1] == Constant.FeedBacks.Paramters.Name
                            || info[1] == Constant.FeedBacks.Paramters.Author)
                            index = 2;
                        else
                            index = 1;

                        for (var i = index; i < info.Count; i++)
                            data += info[i] + " ";

                            if (EngineInfoWindow != null)
                                EngineInfoWindow.Content += data + Environment.NewLine;

                        break;
                    }
                case Constant.FeedBacks.Info:
                    {
                        var depth = 0;
                        var score = 0;
                        double time = 0;

                        var depthIndex = info.IndexOf(Constant.FeedBacks.Paramters.Depth);
                        if (depthIndex >= 0)
                        {
                            depth = info[depthIndex + 1].ToInt32();
                            StatusBarContent.Depth = depth;
                        }
                        
                        var scoreIndex = info.IndexOf(Constant.FeedBacks.Paramters.Score);
                        if (scoreIndex >= 0)
                        {
                            score = info[scoreIndex + 1].ToInt32();
                            StatusBarContent.Score = score;
                        }
                        
                        var timeIndex = info.IndexOf(Constant.FeedBacks.Paramters.Time);
                        if (timeIndex >= 0)
                        {
                            time = info[timeIndex + 1].ToDouble()/1000;
                            StatusBarContent.Time = time;
                        }

                        var currMoveIndex = info.IndexOf(Constant.FeedBacks.Paramters.CurrentMove);
                        if (currMoveIndex >= 0)
                        {
                            StatusBarContent.CurrentMove = info[currMoveIndex + 1];
                        }

                        var curreMoveNumer = info.IndexOf(Constant.FeedBacks.Paramters.CurrentMoveNumber);
                        if(curreMoveNumer >= 0)
                        {
                            StatusBarContent.CurrentMoveNumber = info[curreMoveNumer + 1].ToInt32();
                        }

                        var npsIndex = info.IndexOf(Constant.FeedBacks.Paramters.Nps);
                        if(npsIndex >=0)
                        {
                            StatusBarContent.Nps = info[npsIndex + 1].ToInt32();
                        }

                        var isBestLineFound = info.IndexOf(Constant.FeedBacks.Paramters.Pv) >= 0;
                        if (isBestLineFound)
                        {
                            var bestMove = new BestMove {Type = BestMoveType.Exact, Depth = depth, Score = score, Time = time};

                            var pvIndex = info.IndexOf(Constant.FeedBacks.Paramters.Pv);
                            if (pvIndex >= 0)
                            {
                                var moveList = new MoveList {StartFen = Board.GetCurrentFen()};

                                var length = info.Count - pvIndex;
                                for (var i = 1; i < length; i++)
                                    moveList.Moves.Add(new Move()
                                                           {
                                                               From = info[pvIndex + i].GetFromPosition(),
                                                               To = info[pvIndex + i].GetToPosition()
                                                           });
                                    //bestMove.Move += info[pvIndex + i] + " ";
                                bestMove.MoveList = moveList;
                            }
                            
                            DrawThinkingMoves(bestMove);

                            if (BestMovesWindow != null)
                                BestMovesWindow.AddMove(bestMove);
                        }

                        break;
                    }
                case Constant.FeedBacks.BestMove:
                    {
                        if(IsAnalyzeMode) return;

                        Board.MovePiece(info[1].GetFromPosition(), info[1].GetToPosition(), PieceMovedType.Engine);
                        break;
                    }
            }

            if (DebugWindow != null)
                DebugWindow.Content += e.Data + Environment.NewLine;
            
        }

        protected void DrawThinkingMoves(BestMove bestMove)
        {
            var moves = new List<Move>();
            if (bestMove.MoveList.Moves.Count > 0)
                moves.Add(bestMove.MoveList.Moves[0]);
            if (bestMove.MoveList.Moves.Count > 1)
                moves.Add(bestMove.MoveList.Moves[1]);

            Board.DrawThinkingMoves(moves);
        }

        private void OnTimerTimeOut(object sender, TimeOutEventArgs e)
        {
            //throw new NotImplementedException();
        }

        #region Bottom Panel
        private void ViewBestMovesWindow(object param)
        {
            var flag = (bool)param;
            if (flag)
            {
                BottomPanelSource.Add(BestMovesWindow);
                BottomPanelSelectedItem = BestMovesWindow;
            }
            else
                BottomPanelSource.Remove(BestMovesWindow);

            CheckBottomPanelVisibility();
        }

        private void ViewCommandWindow(object param)
        {
            var flag = (bool)param;
            if (flag)
            {
                BottomPanelSource.Add(CommandWindow);
                BottomPanelSelectedItem = CommandWindow;
            }
            else
                BottomPanelSource.Remove(CommandWindow);

            CheckBottomPanelVisibility();
        }

        private void BottomPanelChildClosed(object param)
        {
            if (BottomPanelSelectedItem != null)
            {
                if (BottomPanelSelectedItem is BestMovesViewModel)
                    IsBestMovesWindowVisible = false;
                else if (BottomPanelSelectedItem is CommandViewModel)
                    IsCommandWindowVisible = false;

                BottomPanelSource.Remove(BottomPanelSelectedItem);
            }

            CheckBottomPanelVisibility();
        }

        private void CheckBottomPanelVisibility()
        {
            IsBottomPanelVisible = BottomPanelSource.Any();
        }

        private bool _isBottomPanelVisible;
        public bool IsBottomPanelVisible
        {
            get { return _isBottomPanelVisible; }
            set
            {
                _isBottomPanelVisible = value;
                RaisePropertyChanged(() => IsBottomPanelVisible);
            }
        }
        #endregion

        #region Right Panel
        private DockableViewModel _rightPanelSelectedItem;
        public DockableViewModel RightPanelSelectedItem
        {
            get { return _rightPanelSelectedItem; }
            set
            {
                _rightPanelSelectedItem = value;
                RaisePropertyChanged(() => RightPanelSelectedItem);
            }
        }

        private void ViewHistoryWindow(object param)
        {
            var flag = (bool)param;
            if (flag)
            {
                RightPanelSource.Add(HistoryWindow);
                RightPanelSelectedItem = HistoryWindow;
            }
            else
                RightPanelSource.Remove(HistoryWindow);

            CheckRightPanelVisibility();
        }

        private void ViewBookMovesWindow(object param)
        {
            var flag = (bool)param;
            if (flag)
            {
                RightPanelSource.Add(BookMovesWindow);
                RightPanelSelectedItem = BookMovesWindow;
            }
            else
                RightPanelSource.Remove(BookMovesWindow);

            CheckRightPanelVisibility();
        }

        private void ViewEngineInfoWindow(object param)
        {
            var flag = (bool)param;
            if (flag)
            {
                RightPanelSource.Add(EngineInfoWindow);
                RightPanelSelectedItem = EngineInfoWindow;
            }
            else
                RightPanelSource.Remove(EngineInfoWindow);

            CheckRightPanelVisibility();
        }

        private void RightPanelChildClosed(object param)
        {
            if (RightPanelSelectedItem != null)
            {
                if (RightPanelSelectedItem is HistoryViewModel)
                    IsHistoryWindowVisible = false;
                else if (RightPanelSelectedItem is BookMovesViewModel)
                    IsBookMovesWindowVisible = false;
                else if (RightPanelSelectedItem is EngineInfoViewModel)
                    IsEngineInfoVisible = false;

                RightPanelSource.Remove(RightPanelSelectedItem);
            }

            CheckRightPanelVisibility();
        }

        private bool _isRightPanelVisible;
        public bool IsRightPanelVisible
        {
            get { return _isRightPanelVisible; }
            set
            {
                _isRightPanelVisible = value;
                RaisePropertyChanged(() => IsRightPanelVisible);
            }
        }

        private bool _isHistoryWindowVisible;
        public bool IsHistoryWindowVisible
        {
            get { return _isHistoryWindowVisible; }
            set
            {
                _isHistoryWindowVisible = value;
                RaisePropertyChanged(() => IsHistoryWindowVisible);
            }
        }

        private bool _isBookMovesWindowVisible;
        public bool IsBookMovesWindowVisible
        {
            get { return _isBookMovesWindowVisible; }
            set
            {
                _isBookMovesWindowVisible = value;
                RaisePropertyChanged(() => IsBookMovesWindowVisible);
            }
        }

        private bool _isEngineInfoVisible;
        public bool IsEngineInfoVisible
        {
            get { return _isEngineInfoVisible; }
            set
            {
                _isEngineInfoVisible = value;
                RaisePropertyChanged(() => IsEngineInfoVisible);
            }
        }

        private void CheckRightPanelVisibility()
        {
            IsRightPanelVisible = RightPanelSource.Any();
        }
        #endregion
    }
}
